package me.keiwu.pub.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Charsets;
import com.google.common.hash.HashCode;
import com.google.common.hash.Hashing;
import jodd.http.HttpResponse;
import me.keiwu.pub.data.ResponseV2;
import me.keiwu.pub.data.wx.WXSessionData;
import me.keiwu.pub.data.wx.WXTemplate;
import me.keiwu.pub.data.wx.WXTemplateData;
import me.keiwu.pub.service.WXService;
import me.keiwu.pub.util.AES;
import me.keiwu.pub.util.HttpUtil;
import me.keiwu.pub.util.wx.TemplateMsgUtil;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;

import java.io.UnsupportedEncodingException;
import java.security.Security;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CyclicBarrier;

/**
 * Created by kei on 27/05/2017.
 */
@Service
public class WXServiceImpl extends WXBaseService implements WXService {

	private static final Logger logger = LoggerFactory.getLogger(WXServiceImpl.class);
	@Autowired
	private TemplateMsgUtil templateMsgUtil;

	static {
		// 初始化Security
		Security.addProvider(new BouncyCastleProvider());
	}

	@Override
	public WXSessionData getSession(String code) {
		Map<String, String> params = new HashMap<>();
		params.put("js_code", code);
		params.put("appid", this.getWxAppId());
		params.put("secret", this.getWxSecret());
		params.put("grant_type", "authorization_code");
		logger.info("getSession info: params={}, url={}", params, this.getWxGetSession());
		try {
			HttpResponse resp = HttpUtil.get(this.getWxGetSession(), params);
			if (resp.statusCode() == HttpStatus.OK.value()) {
				return JSONObject.parseObject(resp.body(), WXSessionData.class);
			}
			logger.error("getSession http fail: {}", resp);
		} catch (UnsupportedEncodingException e) {
			logger.error("getSession error: ", e);
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public boolean checkData(String data, String signature, String sessionKey) {
		HashCode hc = Hashing.sha1().newHasher().putString(data, Charsets.UTF_8).putString(sessionKey, Charsets.UTF_8)
				.hash();
		return hc.toString().equals(signature);
	}

	@Override
	public String decryptData(String encryptedData, String iv, String sessionKey) {
		logger.info("encryptedData null?={}, iv={}, sessionKey={}", encryptedData == null, iv, sessionKey);
		try {
			byte[] resultByte = AES.decrypt(Base64.getDecoder().decode(encryptedData),
					Base64.getDecoder().decode(sessionKey), Base64.getDecoder().decode(iv));
			if (null != resultByte && resultByte.length > 0) {
				return new String(resultByte, "UTF-8");
			}
			logger.error("decryptData resultByte is null");
		} catch (Exception e) {
			logger.error("encode wx data error: ", e);
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public <T> T decryptData(String encryptedData, String iv, String sessionKey, Class<T> clazz) {
		String data = this.decryptData(encryptedData, iv, sessionKey);
		if (data == null)
			return null;
		return JSON.parseObject(data, clazz);
	}

	private static void pressureTest() {
		int count = 500;
		CyclicBarrier barrier = new CyclicBarrier(count, () -> System.out.println("start task"));

		for (int i = 0; i < count; i++) {
			int finalI = i;
			new Thread(() -> {
				try {
					barrier.await();
					// 业务
					decodeData(finalI);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}).start();
		}

	}

	private static void decodeData(int i) {
		long start = System.currentTimeMillis();
		System.out.println("decode start: " + i);
		String sessionKey = "r4B1HGNPkvtEMo8WhR722Q==";
		String data = "62peq/f3+g6Q4tKiZ5Z4yemoXGjxITu6J31JO1yFEUT78cSDrkDvQknNqAl2UFVr8X/fy/MgDCOUAL/2DYcBuFSIgRHQqlL0c3uh8HWuDTg+IGqEvZpVC0UrBJcsj1OcQkbtyD+LVe1YxzIgna3IXgOXxpk2EkBnSECJs3vI46DbtoiiLrzySspjtVwmy50CoNQN5nUTFLeIUDY4nz6rp5TcuAJw4oqt6Obs12SJW28349BpCQnd5AB1jC17//1AvhEPSBFBQnnGwHpa3NO4kPa0C2MPpHO0oXtAxOsIFB7RFi7trEv50qtR2ouadJvZAhrSIp01mwxuHcZh+JLe2M/u6mCD1+BbSERS4ADp8b8vkF37nxKhAFMpHtynM9jyVIOd5loSK+Xp8H+iDfKaI2NEyxYHKD3bWzHQWMm98MJcA03C7oEQmrwuC98zMNOcanEXmP0CQofnIpNXsJiVMbTlwEQbV6ryX9Qf3GmQt9+orLY3+FmEPKz8akLxpV4dZzTNOqZidbR4N1cbfL8dCsyjVZcDGVGwmk0XMVs/OYf2SlecItD5byty37NJrnXuvpxb9IcZH0YHRKEQAo0i+8OErPBkSJk8PuQ+pznZLGaPxC4mP0Mpt0DzuQGOtvayvFHVW183v1Ii2Q5Flcy1asluBPWG0W+YDgINVihemV0xNpnjwHrpU38fPyWkY8TWwy1PQpwn3Ty6iRRUk9yvrxE0Ry7Lqub31owjaTpzlIeTH+8s9x+sc7CZb9YqvW2tinwMgAhZyrliFrsIyO5wNiG5aiAdiLIfpXpblEJcDUZYoPEI0pd0/LtIfZJl6IMWYNnFXLfP/Ms3a/kRFEAg8SGI+NrN7rwvZp202fhjnsE4iiGw6Xq7n/db67Fo9VElucCR7xE/soNqW4E2TFB5QvuwchKTLqUnIfLbEjYiwmmUgNcHPlM++0Nr5vx4SRitZ17VHt+gwylfVInSYyDMt0+wYpDpkeywgoucBNviHfLyWthrZ/4Bdwj8UtwlQWiObx0AGeDJbMH5TQPgKbW2SPfl6vqrLB/mC97NdpU+k5WW2L80h/URKGra9n1HOHJjs92gFYMysXSW0pgmjdicg8vTBeoc5fDqYnPc96WibyW7CmWtk9JIYh+nQxILwfJWQ5fOCOBA+pqbhSuTmu81Hoq26WgfoVhH+pDBiD/UnfzVtkFmQxAQD17rOXJomnNhCbenSeW0qFu20p6bKPVc6vbrtfkxd8jBuI5EF8Dh0uz0Jk+X2NcRmz2m5+h8RVS5IZU6WNFEEgf7JWXu8+2Eng1IiGJhIz3A84KMg8cuM5jBDPIBI8S1UXVKeGsLIxekw4vS2PXowsiIWWvULiSNiIHkacDpMVFJ2eA58lP8//jZ00KcmwtMIgrMCBxUbBqvmO6JuOjeG8Lk2sgKaltLS33hcphPYulnfElNN6rwYtelZUQZ1n7r5IWiH8tcVybORUb+WWBIYQGVS4NCq/erKuLKuxkzGLMefJ7hP4EmO9rdp6ke7jkRu8pyDcfdYIYNZtAED4BOXcUpYq7x8qfxb+D53elv/63mRAwPh3lFfBPiIajFAbA6Vdrjiq8PXz55PGnlA1q4mHHmGX/pVHCkCQkmvQ03UYq9i+EXBpjpinb5SuNK6qTa3w45E0+z3D4I";
		String iv = "UTuRjeRQE9wHM7OkVTwZsA==";
		WXServiceImpl service = new WXServiceImpl();
		String res = service.decryptData(data, iv, sessionKey);
		System.out.println("decode finished: " + i + ", cost: " + (System.currentTimeMillis() - start) / 1000.0);
	}


	@SuppressWarnings("unchecked")
	@Override
	public ResponseV2 sendTemplateMsg(String fromUserJsonStr, String toUserJsonStr, String page, Map<String, Object> paramMap){
		Map<String, Object> templateMap = templateMsgUtil.getTemplate(fromUserJsonStr,toUserJsonStr,paramMap);
		String responseMsg = "empty template data";
		if (templateMap != null){
			Map<String, WXTemplateData> data = new HashMap<String, WXTemplateData>();
			String templateId = (String) templateMap.get("templateId");
			String openId = (String) templateMap.get("openId");
			String formId = (String) templateMap.get("formId");

			data = (Map<String, WXTemplateData>) templateMap.get("data");
			WXTemplate template = new WXTemplate();
			template.setToUser(openId);
			template.setTemplateId(templateId);
			template.setPage(page);
			template.setFormId(formId);
			template.setData(data);
			template.setEmphasisKeyword((String) templateMap.get("emphasisKeyword"));

			String jsonMsg = JSONObject.toJSON(template).toString();
			// 获取请求的url
			String requestUrl = templateMsgUtil.getRequestUrl();
			// 发送模板消息
			HttpResponse resp = HttpUtil.post(requestUrl, jsonMsg);
			if (resp.statusCode() == HttpStatus.OK.value()) {
				@SuppressWarnings("unchecked")
				Map<String, Object> itemMap = JSONObject.parseObject(resp.body(), Map.class);
				// 判断是否发送成功
				if ((int)itemMap.get("errcode") == 0) {
					StringBuilder sbMsg = new StringBuilder("successed: ");
					sbMsg.append(templateId);
					sbMsg.append(" to ");
					sbMsg.append(openId);
					sbMsg.append(" with ");
					sbMsg.append(formId);
					responseMsg = sbMsg.toString();
					return ResponseV2.ok(responseMsg);
				} else if((int)itemMap.get("errcode") == 41029) {
					return ResponseV2.ok(1 , "formId was userd");
				} else {
					StringBuilder sbMsg = new StringBuilder("failed: ");
					sbMsg.append(templateId);
					sbMsg.append(" to ");
					sbMsg.append(openId);
					sbMsg.append(" with ");
					sbMsg.append(formId);
					sbMsg.append(" errcode ");
					sbMsg.append(itemMap.get("errcode"));
					responseMsg = sbMsg.toString();
					return ResponseV2.fail(responseMsg);
				}
			}
			responseMsg = "request wxserver faild: " + resp.body();
			return ResponseV2.fail(responseMsg);
		}
		return ResponseV2.fail(responseMsg);
	}

	public static void main(String[] args) {
		pressureTest();
		// System.out.println(RandomStringUtils.randomAlphanumeric(16));
	}

}
